package com.starlink.common.log.util;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.starlink.common.log.ApplicationLogContext;
import com.starlink.common.log.configuration.WebhookConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;


@Slf4j
public class LarkMessageUtil implements InitializingBean {
    @Autowired
    private ApplicationLogContext applicationLogContext;

    @Autowired
    private WebhookConfiguration webhookConfiguration;

    private TaskExecutor taskExecutor;

    private  final static String SIGN_FORMAT = "{\"timestamp\":\"%s\",\"sign\":\"%s\",\"msg_type\":\"text\",\"content\":{\"text\":\"%s\"}}";

    /**
     * webhook消息发送
     * @param message
     */
    public void sendMessage(String message) {
        if(webhookConfiguration.getEnabled()){
            CompletableFuture.runAsync(()-> sendSignTextMessage(message),taskExecutor);
        }
    }

    public void  sendWarningMessage(Exception ex){
        if(webhookConfiguration.getEnabled()){
            StringBuilder stringBuilder = new StringBuilder(1024);
            stringBuilder.append("报错时间: ").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            stringBuilder.append("\\nserverName: ").append(MDC.get("serverName"));
            stringBuilder.append("\\nuri: ").append(MDC.get("uri"));
            stringBuilder.append("\\ncurrentuser: ").append(MDC.get("current user"));
            stringBuilder.append("\\ntraceId: ").append(MDC.get("traceId"));
            stringBuilder.append("\\nqueryString: ").append(MDC.get("queryString"));
            stringBuilder.append("\\nlocalIP: ").append(MDC.get("localIP"));
            stringBuilder.append("\\nremoteIP: ").append(MDC.get("remoteIP"));
            stringBuilder.append("\\nexception: ").append(ex.toString());
            CompletableFuture.runAsync(()-> sendSignTextMessage(stringBuilder.toString()),taskExecutor);
        }

    }

    @Override
    public void afterPropertiesSet(){
        if(webhookConfiguration.getEnabled()){
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            //核心线程池大小
            taskExecutor.setCorePoolSize(5);
            //最大线程数
            taskExecutor.setMaxPoolSize(10);
            taskExecutor.setQueueCapacity(10);
            //活跃时间
            taskExecutor.setKeepAliveSeconds(60);
            //线程名字前缀
            taskExecutor.setThreadNamePrefix(applicationLogContext.getApplicationName()+"-ExceptionWarning-");
            //配置TaskDecorator传递MDC中数据
            taskExecutor.setTaskDecorator(runnable -> {
                Map<String, String> previous = MDC.getCopyOfContextMap();
                return () -> {
                    try {
                        if (previous != null) {
                            MDC.setContextMap(previous);
                        }
                        runnable.run();
                    } finally {
                        MDC.clear();
                    }
                };
            });
            //当调度器shutdown被调用时等待当前被调度的任务完成
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            // setRejectedExecutionHandler：当pool已经达到max size的时候，如何处理新任务
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
            taskExecutor.initialize();
            this.taskExecutor=taskExecutor;
        }

    }

    private void sendSignTextMessage(String message) {
        final String timestamp = String.valueOf(LocalDateTime.now().toEpochSecond(OffsetDateTime.now ( ZoneId.systemDefault () ).getOffset()));
        String msg = String.format(SIGN_FORMAT, timestamp, getSign(timestamp, webhookConfiguration.getSecretKey()), message);
        HttpResponse execute = HttpUtil.createPost(webhookConfiguration.getUrl()).header("Content-Type", "application/json").body(msg).execute();
        log.info(execute.body());
    }

    private static String getSign(String timestamp,String secret){
        String key=timestamp+"\n"+secret;
        try {
            return hMacSha256("",key);
        }catch (Exception e){
            throw new RuntimeException("生成签名失败");
        }
    }
    public static String hMacSha256(String data, String key) throws Exception {

        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");

        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");

        sha256_HMAC.init(secret_key);

        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(array);

    }

}
